home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 June: Reference Library / Dev.CD Jun 99 RL Disk 1.toast / Technical Documentation / Macintosh Technotes and Q&As / technotes / tn / Apple_Guide_Variables / AG Variables - Read me next >
Encoding:
Text File  |  1997-12-10  |  20.3 KB  |  515 lines  |  [TEXT/R*ch]

  1. Variable Storage in Apple Guide
  2.  
  3. Written By : Don Swatman, Developer Technical Support
  4.  
  5. Copyright: © 1996 by Apple Computer, Inc. All rights reserved.
  6.  
  7. What the sample shows
  8.  
  9. This code sample demonstrates several important techniques that can be used in the creation of a guide file. It demonstrates how to write a background only helper application and how to use it to store and access variables which are used by the guide. In addition it shows how to add a coach mark handler.
  10.  
  11.  
  12. Why you might want to store variables
  13.  
  14. Apple Guide has many advantages over other help systems but has several drawbacks. One is that it is not easy to keep track of what the user has already done. This becomes a particular problem if you are writing a tutorial. For example, your tutorial might have 10 different lessons which the user may need to complete over several days. How can the user be sure that they have gone back to the point where they left the tutorial and not skipped stages? One way to do this is to store variables within an application.
  15.  
  16.  
  17. Why you might want to use a helper application
  18.  
  19. It is not always possible for the guide author to have access to the application's source. This is especially true if they are writing a guide for somebody else's application.  You may also want to add complex Apple Events to an application that has been factored but not fully scripted. The way to do this is to write a small background only application referred to as a helper application. Your guide sends Apple Events or context checks to the helper application and in turn the helper app makes changes, creates complex events, etc. and passes these on to the application. In this sample the helper application is used to store variables. The background only application is based on the SmallDaemon sample on the toolchest CD. This was originally written by Greg Robbins based on code by C.K. Haun.
  20.  
  21. How to use the Tutorial
  22.  
  23. Double click "Open this App" and open the tutorial in the help menu. Apple Guide will start up presenting you with a single list access window. The application is nothing more than a simple shell application that allows you to open several windows.
  24.  
  25. "Tutorial"
  26.  
  27.         "From Start"
  28. This will take you through each lesson in order, regardless whether you've completed the lesson already.
  29.  
  30.         "Skip completed lessons"
  31. This will only take you through each lessons that have NOT been completed.
  32.  
  33.         " Lesson 1",
  34.    " Lesson 2",
  35.    " Lesson 3"
  36. Lets you go straight to a lesson whether you have seen it already or not.
  37.  
  38. House Keeping
  39.  
  40.         "Reset the Lesson plan"
  41. This clears all previously completed lessons.
  42.  
  43.         "What is the Lesson Status"
  44. Lets you find out which lessons if any have been completed.
  45.  
  46. Scripts
  47.  
  48. "StartHelperApp"
  49. This script will start the background only application called "AGHelperApp".
  50.  
  51. "QuitHelperApp"
  52. This script will quit the background only application called "AGHelperApp".
  53.  
  54. Building
  55.  
  56. "AGHelperApp" compiles under :
  57.     Metrowerks CodeWarrior 9 68K and PPC
  58.     MPW E.T.O. #20- Symantec C++ for MPW, MrC
  59.  
  60. MPW build notes
  61.  
  62. Before building you need to move AppleGuideGlueLib.xcoff from Dev.CD Jul 96 SDK1:Development Kits (Disc 1):Apple Guide:Engineering:Interfaces: to MPW's PPCLibraries  folder.
  63. "AGHelperApp.make" builds a fat version of the helper application.
  64.  
  65. Metrowerks build notes
  66.  
  67. "AGHelperApp MW-PPC.µ" build a PPC version of the application.
  68. "AGHelperApp MW-68k.µ" build a 68k version of the application.
  69.  
  70.  
  71. Files
  72.  
  73. AGHelper App Source
  74.  
  75. AGHelper.c
  76.     - Was originally called cSmallDaemon
  77.     - Contains "main" function which has the calls to install and remove AGValues.
  78.     - Handles the event loop
  79.  
  80. AGValues.c,
  81. AGValues.h
  82.     - Contains the code for Apple Events and context checks to allow Apple Guides to store and retrieve variables.
  83.     - Installs and removes Apple Events and context check handlers
  84.  
  85. AGHelper.r
  86.     - Contains the 'SIZE' resources in a text format. This is used by the MPW make files.
  87.  
  88. Guide Source
  89.  
  90. Content
  91.     - Contains all the Apple Script commands to build the tutorial guide
  92.  
  93. Resources,
  94. Setup
  95.     - cut down versions of the Standard Resources and Standard Setup
  96.  
  97. Apple Script Source
  98.  
  99. StartHelperApp,
  100. StartHelperApp Text
  101.     - Compiled and text version of a script that launches AGHelperApp
  102.  
  103. QuitHelperApp,
  104. QuitHelperApp Text
  105.     - Compiled and text version of a script that quits AGHelperApp
  106.  
  107.  
  108. How the interesting stuff works
  109.  
  110. How to write context check handlers
  111.  
  112. Context checks are defined in Apple Script in the following format. 
  113.  
  114.   <Define Context Check> ContextCheckName, codeResSpec [ , targetApp ]
  115.                              [, additionalParam ] [, additionalParam ]
  116.  
  117. Note that you can use <DCC> as an abbreviation. The targetApp's context check handler called coderResSpec will be called and passed any additional parameters. Information about additional parameters can be found on page 10-173 of Apple Guide complete. If you want to default one or more of the additional parameters, after the parameter type add a colon, then the default value. For example, the follow checks will all do the same thing - send check 'Chck' to application 'MyAp' with the parameters 13 and 15:
  118.  
  119.   <DCC> "Check_2_Longs", 'Chck', 'MyAp', LONG, LONG
  120.   <If> (Check_2_Longs(13,15))
  121.  
  122.   <DCC> "Check_1st_Default", 'Chck', 'MyAp', LONG:13, LONG
  123.   <If> (Check_1st_Default(15))
  124.  
  125.   <DCC> "Check_2nd_Default", 'Chck', 'MyAp', LONG, LONG:15
  126.   <If> (Check_2nd_Default(13))
  127.  
  128.   <DCC> "Check_Both_Default", 'Chck', 'MyAp', LONG:13, LONG:15
  129.   <If> (Check_Both_Default())
  130.  
  131. The applications context check handler can be installed with the following:
  132.  
  133.   theErr = AGInstallContextHandler( NewContextReplyProc(MyContextCallBack),
  134.                                     'Vals', 0, &contextRefNum );
  135.  
  136.  
  137. MyContextCallBack is the function name of the handler, 'Vals' is used to identify it and corresponds to the codeResSpec in the guides <DCC> command, the 0 is a refcon which in this case isn't used and contextRefNum is a global that will be needed when the application quits. To remove the handler use
  138.  
  139.   theErr = AGRemoveContextHandler( &contextRefNum );
  140.  
  141. The context check handler must be in the following format.
  142.  
  143.   pascal OSErr MyContextCallBack( Ptr   pInputData,
  144.                                                                                                           Size  inputDataSize,
  145.                                                                                                           Ptr   *ppOutputData,
  146.                                                                                                           Size  *pOutputDataSize,
  147.                                                                                                           AGAppInfoHdl hAppInfo )
  148.  
  149.  
  150. pInputData and inputDataSize are used to pass the additional parameters from the guide file. ppOutputData and pOutputDataSize are used to return the information. hAppInfo contains information about the codeResSpec and the refCon. 
  151.  
  152. The additional parameters are passed in pInputData and inputDataSize and a structure should be created that matches them. Therefore, if the additional parameters contained two longs, then the structure should contain longs. Using an example from above, the structure would need to be: 
  153.  
  154.   struct PassedAGParamType
  155.   {
  156.     long firstParameter;
  157.     long secondParameter;
  158.   };
  159.  
  160.   typedef struct PassedAGParamType PassedAGParamType,
  161.                  *PassedAGParamPtr, **PassedAGParamHdl;
  162.  
  163. The context check needs to evaluate the parameters passed to it and then decide whether it needs to return true or false. This is passed back in ppOutputData and pOutputDataSize, however as this is part of a far wider mechanism you can't simply pass back the Boolean but you must create a pointer and move the Boolean's value into it. There is a routine in the sample that does all the work for you. Note that Apple Guide is responsible for de-allocating this pointer not the helper app.
  164.  
  165.   OSErr MySetContextResult( Boolean result,
  166.                             Ptr     *outMessage,
  167.                             Size    *outSize )
  168.   {
  169.     Ptr   pOut;
  170.     Size  theSize = sizeof ( Boolean );
  171.     OSErr theErr = noErr;
  172.     
  173.     pOut = NewPtr (theSize);
  174.     if ( pOut )
  175.     {
  176.       BlockMove( (void *)&result, pOut, theSize );
  177.       *outSize = theSize;
  178.       *outMessage = pOut;
  179.     }
  180.     else
  181.       theErr = MemError();
  182.     return theErr;    
  183.   }
  184.  
  185. In the context check:
  186.  
  187.     ...
  188.     ...
  189.   // Set up the return values ppOutputData and pOutputDataSize
  190.  
  191.     theErr = MySetContextResult ( checkResult, ppOutputData, pOutputDataSize );
  192.     
  193.     return theErr;
  194.   }
  195.  
  196.  
  197. How to write Apple Guide coach handlers
  198.  
  199. Coach marks are defined in Apple Script in the following format. 
  200.  
  201.   <Define Object Coach> CoachMarkName, targetApp [, coachStyle] [, objectName ]
  202.  
  203. Note that you can use <DOC> as an abbreviation. The objectName will be passed to the targetApp's coach mark handler. This is installed by:
  204.  
  205.   theErr = AGInstallCoachHandler( NewCoachReplyProc(MyObjectCoachCallBack),
  206.                                   0, &coachRefNum );
  207.  
  208. MyObjectCoachCallBack is the function name of the handler, the 0 is a refcon which in this case isn't used and coachRefNum is a global that will be needed when the application quits. To remove the handler use
  209.  
  210.   theErr = AGRemoveCoachHandler( &coachRefNum );
  211.  
  212. The coach mark handler must be in the following format:
  213.  
  214.   pascal OSErr MyObjectCoachCallBack ( Rect *pRect, Ptr name, long refCon )
  215.   {
  216.     OSErr theErr = noErr;    
  217.  
  218.     SetRect ( pRect, 100,100, 200,200);    
  219.     return theErr;
  220.   }
  221.  
  222. The object name from the guide is passed to the handler in the name parameter. It arrives as a null terminated string and can be interrogated to find out which object you wish to access. You must then return its rect in global coordinates in pRect. As this is a demonstration, it only returns a 100*100 rect.
  223.  
  224. What's been done to SmallDaemon
  225.  
  226. Very few changes have been made to the original sample, except to make it compile under the latest compilers. The biggest change is to add the calls that install and remove AGValues to main(). The bulk of the changes are in the files AGValues.c and AGValues.h.
  227.  
  228. Globals
  229.  
  230. Storage has been provide for 100 variables. In 'C' this provides an array from 0-99, however in the guide we are going to use values of 1-3. For neatness sake, these will be mapped from 1-3 to 0-2.
  231.  
  232.    #define kMaxAGEntries 100  
  233.   long gAGValues[kMaxAGEntries];
  234.  
  235. Also references must be stored for the coach mark and context check handlers:
  236.  
  237.   AGCoachRefNum   coachRefNum;
  238.   AGContextRefNum contextRefNum;
  239.  
  240.  
  241. How to install and remove the handlers
  242.  
  243. The handlers are installed by InitAGStuff. First it clears all the stored variables. Then it installs a coach mark handler, a context check handler and then the Apple Events.
  244.  
  245.   OSErr InitAGStuff()
  246.   {
  247.     OSErr theErr = noErr;
  248.     short count;
  249.     
  250.   // Clear all the values stored by the application
  251.     ClearAllAGValues();
  252.         
  253.   // Install object coach handler
  254.     theErr = AGInstallCoachHandler( NewCoachReplyProc(MyObjectCoachCallBack),
  255.                                     0, &coachRefNum );
  256.     if (theErr)
  257.       DebugStr("\pGot an Err - AGInstallCoachHandler ");
  258.             
  259.   // Install context check handler. MyContextCallBack will get called when a 
  260.   // context check of 'Vals' is queried by the Guide
  261.  
  262.     theErr = AGInstallContextHandler( NewContextReplyProc(MyContextCallBack),
  263.                                       'Vals', 0, &contextRefNum );
  264.     if (theErr)
  265.       DebugStr("\pGot an Err - AGInstallContextHandler ");
  266.     
  267.   // set up the dispatch table for the AppleEvents
  268.     theErr = AEInstallEventHandler( 'Vals', 'Cler', NewAEEventHandlerProc(ClearAGValues),
  269.                                     0, false) ;
  270.  
  271.     theErr = AEInstallEventHandler( 'Vals', 'Clr1', NewAEEventHandlerProc(ClearAGValues1),
  272.                                     0, false) ;
  273.     theErr = AEInstallEventHandler( 'Vals', 'Clr2', NewAEEventHandlerProc(ClearAGValues2),
  274.                                     0, false) ;
  275.     theErr = AEInstallEventHandler( 'Vals', 'Clr3', NewAEEventHandlerProc(ClearAGValues3),
  276.                                     0, false) ;
  277.  
  278.     theErr = AEInstallEventHandler( 'Vals', 'Set1', NewAEEventHandlerProc(SetAGValues1),
  279.                                     0, false) ;
  280.     theErr = AEInstallEventHandler( 'Vals', 'Set2', NewAEEventHandlerProc(SetAGValues2),
  281.                                     0, false) ;
  282.     theErr = AEInstallEventHandler( 'Vals', 'Set3', NewAEEventHandlerProc(SetAGValues3),
  283.                                     0, false) ;
  284.     
  285.     return theErr;
  286.   }
  287.  
  288. Before the application quits, it should remove any Apple Guide handlers that have been installed .
  289.  
  290.   void RemoveAGStuff()
  291.   {
  292.     OSErr theErr;
  293.  
  294.     theErr = AGRemoveContextHandler( &contextRefNum );
  295.     theErr = AGRemoveCoachHandler( &coachRefNum );
  296.   }
  297.  
  298. Setting and clearing variables
  299.  
  300. Setting and clearing of the variables is done by Apple Events. Each event has a specific ID and no passed parameters. You will probably need to make these obvious by their ID. For instance to set and clear value 1, use the event ID's 'Set1' and 'Clr1' . The Apple Event handlers would look like the following:
  301.  
  302.   pascal OSErr SetAGValues1 ( const AppleEvent *message,
  303.                               const AppleEvent *reply,
  304.                                     long        refcon )            
  305.   {
  306.     gAGValues[0] = 1;
  307.     return( noErr );
  308.   }
  309.  
  310.   pascal OSErr ClearAGValues1 ( const AppleEvent *message,
  311.                                 const AppleEvent *reply,
  312.                                       long        refcon )            
  313.   {
  314.     gAGValues[0] = 0;
  315.     return( noErr );
  316.   }
  317.  
  318. The event for clearing all the variables is 'Cler'.
  319.  
  320.   pascal OSErr ClearAGValues ( const AppleEvent *message,
  321.                                const AppleEvent *reply,
  322.                                      long        refcon )            
  323.   {
  324.     ClearAllAGValues();
  325.     return( noErr );
  326.   }
  327.  
  328.  
  329. Interrogating variables
  330.  
  331. Checking the state of the variables is handled by Apple Guide context checks. Two parameters - in this case longs - are passed by the guide file to the application. 
  332.  
  333.   struct PassedAGParamType
  334.   {
  335.     long command;
  336.     long index;
  337.   };
  338.  
  339.   typedef struct PassedAGParamType PassedAGParamType,
  340.                   *PassedAGParamPtr, **PassedAGParamHdl;
  341.  
  342. If the first parameter, command, contains a 0, then a check is made to see if the value is 0. If it contains a 1, then the check sees it the value is non-0. Index is used to define which variable to check. The full context check looks like the following:
  343.  
  344.   pascal OSErr MyContextCallBack( Ptr   pInputData,
  345.                                   Size  inputDataSize,
  346.                                   Ptr   *ppOutputData,
  347.                                   Size  *pOutputDataSize,
  348.                                   AGAppInfoHdl hAppInfo )
  349.   {
  350.     OSErr   theErr = noErr;
  351.     Boolean checkResult = false;
  352.  
  353.   // Check the index is within range
  354.     if (((PassedAGParamPtr)pInputData)->index <= kMaxAGEntries)
  355.     {
  356.  
  357.   // Work out whether we need to return true or false
  358.       if (((PassedAGParamPtr)pInputData)->command == 1)
  359.         checkResult = gAGValues[ ((PassedAGParamPtr)pInputData)->index - 1 ] != 0;
  360.       else
  361.         checkResult = gAGValues[ ((PassedAGParamPtr)pInputData)->index - 1 ] == 0;
  362.     }
  363.     
  364.   // Set up the return values ppOutputData and pOutputDataSize
  365.  
  366.     theErr = MySetContextResult ( checkResult, ppOutputData, pOutputDataSize );
  367.     
  368.     return theErr;
  369.   }
  370.  
  371. How the guide makes use of these added features
  372.  
  373. Defining the Events in the guide and using them
  374.  
  375. To make use of the events defined in the application, you need to define the events in the guide:
  376.  
  377.   <Define Event> "ClearValues", 'AgHp', 'Vals', 'Cler'
  378.   <Define Event> "SetFlag1",    'AgHp', 'Vals', 'Set1'
  379.   <Define Event> "ClearFlag1",  'AgHp', 'Vals', 'Clr1'
  380.   <Define Event> "SetFlag2",    'AgHp', 'Vals', 'Set2'
  381.   <Define Event> "ClearFlag2",  'AgHp', 'Vals', 'Clr2'
  382.   <Define Event> "SetFlag3",    'AgHp', 'Vals', 'Set3'
  383.   <Define Event> "ClearFlag3",  'AgHp', 'Vals', 'Clr3'
  384.   <Define Event> "SetFlag4",    'AgHp', 'Vals', 'Set4'
  385.   <Define Event> "ClearFlag4",  'AgHp', 'Vals', 'Clr4'
  386.  
  387. "ClearValues" sends the Apple Event 'Cler' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to clear all variables to 0.
  388.  
  389. "SetFlag1" sends the Apple Event 'Set1' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to set the first variables to 1.
  390.  
  391. "ClearFlag1" sends the Apple Event 'Clr1' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to set the first variables to 0.
  392. etc.
  393.  
  394. To use them, use an <On Panel Hide>, for example:
  395.  
  396.   <On Panel Hide> SetFlag1()
  397.  
  398. Defining the context checks in the guide
  399.  
  400. Context checks are defined to find out whether any variable is set or cleared, or specific variables are set.
  401.  
  402.   <DCC> "IsFlagSet",    'Vals', 'AgHp', LONG:1, LONG
  403.   <DCC> "IsFlagClear",  'Vals', 'AgHp', LONG:0, LONG
  404.  
  405.   <DCC> "Flag1Set",     'Vals', 'AgHp', LONG:1, LONG:1
  406.   <DCC> "Flag2Set",     'Vals', 'AgHp', LONG:1, LONG:2
  407.   <DCC> "Flag3Set",     'Vals', 'AgHp', LONG:1, LONG:3
  408.  
  409. If you want to check whether the first variable has been set, you can use one of two checks:
  410.  
  411.     <If> ( isFlagSet( 1 ) )
  412.  
  413.     <If> ( Flag1Set() )
  414.  
  415. Note that because the parameters have default values in the definitions, those parameters are not included when they are used.
  416.  
  417. Making sure the helper app is launched
  418.  
  419. To make sure the helper app is launched you need to trigger it from an Apple Script. You may also want to use a script to make it quit. The script needs to be compiled. Note that if you change the helper, or main app's creator, you will need to recompile the script and then recompile the guide. The script that starts the helper app is called "StartHelperApp". It contains the following Apple Script commands :
  420.  
  421.   tell application "AGHelperApp"
  422.     launch
  423.   end tell
  424.  
  425. The script that quits the app, is "QuitHelperApp". It contains the following Apple Script commands :
  426.  
  427.   tell application "AGHelperApp"
  428.     quit
  429.   end tell
  430.  
  431. Once compiled the scripts need to be triggered before the events and context checks can be used. For example the first panel in "Tutorial Skip lessons" sequence called "Tutorial Intro" :
  432.  
  433.   <Define Panel> "Tutorial Intro"
  434.   <On Panel Create> DoAppleScript( "StartHelperApp" )
  435.   This is the first panel in the tutorial.
  436.   It launches the helper App.
  437.   <End Panel>
  438.  
  439. Skipping Completed Sequences
  440.  
  441. The "Tutorial Skip lessons" sequence demonstrates a sequence that will take you through a tutorial and skip sequences that have already been done.
  442.  
  443.   <Define Sequence> "Tutorial Skip lessons", "Tutorial"
  444.     <Panel> "Tutorial Intro"
  445.  
  446.     <If> NOT Flag1Set()
  447.       <Jump Sequence> "Lesson 1"
  448.     <End If>
  449.   
  450.     <If> NOT Flag2Set()
  451.       <Jump Sequence> "Lesson 2"
  452.     <End If>
  453.  
  454.     <If> NOT Flag3Set()
  455.       <Jump Sequence> "Lesson 3"
  456.     <End If>
  457.  
  458.     <Panel> "Tutorial Outro"
  459.   <End Sequence>
  460.  
  461.  
  462. Marking a sequence as completed
  463.  
  464. To mark a sequence completed,  use an <On Panel Hide> command with a suitable event to set the variable . For example to mark the sequence "Lesson 1" as completed, the last panel contains:
  465.  
  466.   <Define Panel> "Lesson 1 Panel Outro"
  467.   <On Panel Hide> SetFlag1()
  468.   Last panel in Lesson 1.
  469.  
  470.   This may contain an acknowledgment that the lesson has been completed.
  471.  
  472.   It sets flag 1 with :
  473.     "<On Panel Hide> SetFlag1()"
  474.   <End Panel>
  475.  
  476.  
  477. Further things YOU could do
  478.  
  479. If you feel like playing with this app, there's a few ways you could improve it.
  480. - Make the sample save all the variables to a preferences file when it quits and re-loads them when it starts
  481. - Implement more variables and different ways of checking them.
  482. - Add AGValues.c to your application and write a tutorial Guide!
  483.  
  484.  
  485. Further Ref
  486.  
  487.  - Apple Guide Complete is an almost essential volume if you are writing Apple Guide help systems. It is published by Addison-Wesley.
  488.  - Apple Guide Variables Technote.
  489.  
  490.  
  491. Acknowledgments
  492.  
  493. Special thanks to :
  494.     Jason Hodges-Harris - for fixing the MPW build
  495.     Greg Robbins & C.K. Haun - for the original SmallDaemon sample
  496.  
  497.  
  498.  
  499. *********************************************************************
  500. **                                                                 **
  501. ** You may incorporate this sample code into your applications     **
  502. ** without restriction, though the sample code has been provided   **
  503. ** "AS IS" and the responsibility for its operation is 100% yours. **
  504. ** However, what you are not permitted to do is to redistribute    **
  505. ** the source as "DSC Sample Code" after having made changes. If   **
  506. ** you're going to re-distribute the source, we require that you   **
  507. ** make it clear in the source that the code was descended from    **
  508. ** Apple Sample Code, but that you've made changes.                **
  509. **                                                                 **
  510. *********************************************************************
  511.  
  512.  
  513. Don Swatman - Aug. 96
  514. © 1996 by Apple Computer, Inc., all rights reserved.
  515.